/* This file is part of GSMC.
 * 
 * GSMC is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * GSMC is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with GSMC.  If not, see <http://www.gnu.org/licenses/>.
 */

package net.hpxn.gsmc.core.event;

import java.io.File;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

import org.apache.log4j.Logger;

import net.hpxn.gsmc.action.BaseAction;
import net.hpxn.gsmc.action.util.ActionClassLoader;
import net.hpxn.gsmc.config.ConfigFactory;
import net.hpxn.gsmc.config.map.Map.Mapping.Action;
import net.hpxn.gsmc.core.ThreadPool;
import net.hpxn.gsmc.core.server.Server;
import net.hpxn.gsmc.core.server.ServerManager;

import net.hpxn.gsmc.config.map.Map.Mapping;

public class EventMonitor implements Runnable {

	private Thread serverThread;
	private boolean isRunning;
	private int listenPort;
	private Logger log;

	private static ActionClassLoader classLoader;

	public EventMonitor() throws Exception {
		log = Logger.getLogger( getClass().getCanonicalName() );
		classLoader = new ActionClassLoader( "actions" + File.separatorChar );
		try {
			listenPort = Integer.valueOf( ConfigFactory.getServerConfigs()
					.getListenPort() );
		} catch ( Exception e ) {
			throw e;
		}
	}

	public void start() {
		isRunning = true;
		serverThread = new Thread( this, "Monitor" );
		serverThread.start();
	}

	public void run() {
		DatagramSocket wSocket = null;
		DatagramPacket wPacket = null;
		byte[] wBuffer = null;

		try {
			wSocket = new DatagramSocket( listenPort );
			wBuffer = new byte[2048];
			wPacket = new DatagramPacket( wBuffer, wBuffer.length );
		} catch ( SocketException e ) {
			log.fatal( "Could not open the socket: \n" + e.getMessage() );
		}

		while ( isRunning ) {
			try {
				wSocket.receive( wPacket );
				log.debug( "Packet receieved." );
				handlePacket( wPacket, wBuffer );
			} catch ( Exception e ) {
				log.error( e.getMessage() );
				e.printStackTrace();
			}
		}
	}

	private void handlePacket( DatagramPacket pPacket, byte[] pBuffer )
			throws Exception {
		String wRemoteAddress = pPacket.getAddress().getHostAddress();
		int wRemotePort = pPacket.getPort();

		String wRawEvent = new String( pBuffer, 0, pPacket.getLength() );

		boolean knownSource = false;

		for ( Server wServer : ServerManager.getServerList() ) {
			if ( wRemoteAddress.equals( wServer.getRemoteIp() )
					&& wRemotePort == wServer.getRemotePort() ) {
				BaseEvent wEvent = EventFactory
						.createEvent( wRawEvent, wServer );
				handleEvent( wEvent );
				knownSource = true;
			}
		}

		if ( !knownSource ) {
			log.warn( "UNKNOWN DATA SOURCE [" + wRemoteAddress + ":"
					+ wRemotePort + "]" );
		}
		pPacket.setLength( pBuffer.length );
	}

	public void handleEvent( BaseEvent pEvent ) throws Exception {
		for ( Mapping wMapping : pEvent.getMappingList() ) {
			for ( Action wAction : wMapping.getActions() ) {
				@SuppressWarnings( "rawtypes" )
				Class c = classLoader.loadClass( wAction.getValue() );
				BaseAction wBaseAction = (BaseAction) c.newInstance();

				wBaseAction.setEvent( pEvent );
				wBaseAction.setMapping( wMapping );

				ThreadPool.getInstance().execute( wBaseAction );
			}
		}
	}

	public boolean isRunning() {
		return isRunning;
	}

	public void setRunning( boolean isRunning ) {
		this.isRunning = isRunning;
	}
}
